package namespace

import (
	"errors"
	"fmt"

	"gddgame.cc/galaxy/binocle"
	. "gddgame.cc/galaxy/common/dsl/game"
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/common/service/pathfinding"
	"gddgame.cc/galaxy/project/breeder/breeder/cooperated"
	"gddgame.cc/galaxy/utils/def"

	"gddgame.cc/galaxy/core/sdk"
	"gddgame.cc/galaxy/project/breeder/breeder/controller"
	"gddgame.cc/galaxy/project/breeder/breeder/model"
	"gddgame.cc/galaxy/satellite/formula/nebula"
	"gddgame.cc/galaxy/server/composer"
)

const (
	ManagerMapCreate nebula.NSE = iota
	ManagerMapUpdate
	ManagerOperationList
	ManagerOperate
	ManagerUnitPut
	ManagerUnitMove
	ManagerUnitDetail
	ManagerCanUnitList
	ManagerCanUnitBuildList
	ManagerUnitChangeBehaviorPattern

	ManagerDataDepend = 100
	ManagerDataNodes  = 101
	ManagerData       = 102
	ManagerDataList   = 103
)

func GetManagerQueryParam(context def.Context) (mapNoId string, err error) {
	if err = context.Get("map_no_id", &mapNoId); err != nil {
		return
	}
	return
}

/*
 游戏地图管理
*/
func ManageHandler(builder composer.Builder, client *sdk.AppClient, namespace nebula.Namespace) {
	var agent binocle.App
	builder.Factory("agent", &agent)

	namespace.SetCompress(true)

	infoNS, _ := namespace.Root().Of(INFO)

	if err := namespace.Connect(func(socket *nebula.Socket, next nebula.Next) {
		var openId string
		err := socket.Get("open_id", &openId)
		if err != nil {
			_ = next(errors.New("Auth error"))
			return
		}
		_ = next(nil)

	}); err != nil {
		builder.Error(err)
	}

	_ = namespace.On(ManagerMapCreate, func(req *nebula.Request, data []byte, name string, content string, people int, aiNumber int) {
		mapItem, err := controller.CreateMap(req, 0, name, content, people, aiNumber, data)
		if err != nil {
			return
		}
		mapData := controller.Env.CooperateManager.ParseMap(data)
		extendMap := cooperated.NewExtendMap()
		if err := extendMap.Parse(mapData.Extend); err != nil {
			fmt.Println("extend map", err)
			return
		}
		nodes := make([]model.MapNode, len(*extendMap.Regions))
		for index, node := range *extendMap.Regions {
			position := pathfinding.DecodeVector2(node)
			nodes[index] = model.MapNode{
				Name:       "",
				X:          int(position.X),
				Y:          int(position.Y),
				DataType:   cooperated.RegionType,
				Mode:       0,
				Status:     true,
				AttrEffect: nil,
			}
		}
		if err := controller.UpdateNode(req, mapItem.Id, mapItem.Version, nodes); err != nil {
			return
		}
		req.Response(mapItem.Id)
	})
	_ = namespace.On(ManagerMapUpdate, func(req *nebula.Request, mapId int, data []byte, people int, aiNumber int) {
		version, err := controller.UpdateMap(req, 0, mapId, people, aiNumber, data)
		if err != nil {
			fmt.Println(err)
			return
		}
		mapData := controller.Env.CooperateManager.ParseMap(data)
		extendMap := cooperated.NewExtendMap()
		if err := extendMap.Parse(mapData.Extend); err != nil {
			fmt.Println("extend map", err)
			return
		}
		nodes := make([]model.MapNode, len(*extendMap.Regions))
		for index, node := range *extendMap.Regions {
			position := pathfinding.DecodeVector2(node)
			nodes[index] = model.MapNode{
				Name:       "",
				X:          int(position.X),
				Y:          int(position.Y),
				DataType:   cooperated.RegionType,
				Mode:       0,
				Status:     true,
				AttrEffect: nil,
			}
		}
		if err := controller.UpdateNode(req, mapId, version, nodes); err != nil {
			return
		}
		req.Response(true)
	})
	_ = namespace.On(ManagerUnitPut, func(req *nebula.Request, unitId int, position []byte, identity int) {
		mapNoId, err := GetManagerQueryParam(req)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		key := controller.Center.TargetKeyMap[cooperated.UnitType][unitId]
		id := controller.Center.TargetIdMap[cooperated.UnitType][key]
		unit := controller.Center.UnitMap[id]
		if identity != cooperated.FirstIdentityType && identity != cooperated.SecondIdentityType && identity != cooperated.ThirdIdentityType {
			req.ResponseErr(errors.New("身份信息错误"))
			return
		}

		result := controller.Center.Signal(mapNoId).OnQuery(0, identity, cooperated.CreateUnit, []interface{}{key, position, unit.Name})
		fmt.Println(result)
		if result != nil {
			switch r := result.(type) {
			case error:
				req.ResponseErr(r)
				return
			}
		}

		req.Response(true)
	})

	// 移动部队
	_ = namespace.On(ManagerUnitMove, func(req *nebula.Request, userUnitId string, moveMode byte, dataType byte, id interface{}) {
		mapNoId, err := GetManagerQueryParam(req)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		result := controller.Center.Signal(mapNoId).OnQuery(0, 0, cooperated.MoveUnit, []interface{}{userUnitId, moveMode, dataType, id})
		fmt.Println("move", userUnitId, moveMode, dataType, id)
		if result != nil {
			req.ResponseErr(result.(error))
			return
		}
		req.Response(true)
	})
	_ = namespace.On(ManagerUnitDetail, func(req *nebula.Request, userUnitId string) {
		var unitDetail *model.PlayerUnitDetail
		var err error

		mapNoId, err := GetManagerQueryParam(req)
		info := controller.Center.GetData(mapNoId, cooperated.UnitType, userUnitId)
		if info == nil {
			req.ResponseErr(controller.Center.LanguageError("UNIT_NOT_EXIST"))
			return
		}
		unit, ok := info.(*cooperated.Unit)
		if !ok {
			req.ResponseErr(controller.Center.LanguageError("UNIT_NOT_EXIST"))
			return
		}
		stat := controller.Center.GetStatData(unit)
		userUnit, err := controller.GetUnitWithUser(req, userUnitId, nil)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		unitDetail, err = controller.GetUnitDetail(req, userUnit, unit, stat)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		fmt.Println(unitDetail)
		req.SetCompress(true)
		req.Response(unitDetail)
	}) // 部队详情
	// 获取操作列表
	_ = namespace.On(ManagerOperationList, func(req *nebula.Request, selectIds []interface{}, dt byte, id interface{}) {
		req.Namespace(infoNS)

		rr, err := namespace.Trigger(InfoOperationList, []interface{}{selectIds, dt, id}, req)
		req.Namespace(namespace)
		if err != nil {
			req.ResponseErr(err)
		} else {
			req.Bind(rr)
		}
	})
	// 执行操作
	_ = namespace.On(ManagerOperate, func(req *nebula.Request, selectIds []interface{}, operateId int, params []interface{}) {
		req.Namespace(infoNS)

		rr, err := namespace.Trigger(InfoOperate, []interface{}{selectIds, operateId, params}, req)
		req.Namespace(namespace)
		if err != nil {
			req.ResponseErr(err)
		} else {
			req.Bind(rr)
		}
	})
	// 获取当前账号可创建的部队列表
	_ = namespace.On(ManagerCanUnitList, func(req *nebula.Request) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.ResponseErr(err)
			return
		}
		unitList := make([]*model.UnitInfo, 0, len(controller.Center.CreateUnits))
		for _, unit := range controller.Center.CreateUnits {
			unitList = append(unitList, unit.Info)
		}
		req.Response(unitList)
	})
	// 获取当前账号可创建的部队列表
	_ = namespace.On(ManagerCanUnitBuildList, func(req *nebula.Request, unitId int) {
		mapNoId, err := GetManagerQueryParam(req)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		userUnit := controller.Center.GetData(mapNoId, cooperated.UnitType, unitId)
		buildList := make([]*model.BuildInfo, 0, len(controller.Center.UnitBuilds))
		for _, build := range controller.Center.UnitBuilds {
			//fmt.Println("build", build.FilterRequireSlice)
			if !controller.ValidRequire(req, build.FilterRequireSlice, nil, nil, nil, userUnit.(*cooperated.Unit)) {
				continue
			}
			buildList = append(buildList, build.Info)
		}
		req.Response(buildList)
	})

	_ = namespace.On(ManagerUnitChangeBehaviorPattern, func(req *nebula.Request, userUnitId int, behaviorPattern byte) {
		mapNoId, err := GetManagerQueryParam(req)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		//if _, err := controller.ChangeUnitAiMode(req, userUnitId, aiMode, &user); err != nil {
		//	return
		//}
		fmt.Println("change bp", userUnitId, behaviorPattern)
		result := controller.Center.Signal(mapNoId).OnQuery(0, 0, cooperated.ChangeBehaviorPattern, []interface{}{userUnitId, behaviorPattern})
		if result != nil {
			req.ResponseErr(result.(error))
			return
		}
		req.Response(true)
	})

	_ = namespace.On(ManagerDataDepend, func(req *nebula.Request, mapNoId string, t byte, id interface{}, key string) {
		list := controller.Center.ListDepend(mapNoId, structure.PublicDataType(t), id, key)
		//fmt.Println("list", id, key, list)
		if list == nil {
			req.Response([]*model.MapItemInfo{})
			return
		}
		items := make([]*model.MapItemInfo, len(list))
		fmt.Println("list", len(list), len(items), list)
		for i, f := range list {
			if f == nil {
				items[i] = nil
				continue
			}
			items[i] = &model.MapItemInfo{
				Id:       f.GetId(),
				DataType: f.GetDataType(),
				Data:     f,
			}
		}
		req.Response(items)
	})
	_ = namespace.On(ManagerDataNodes, func(req *nebula.Request, mapNoId string, t byte, id interface{}, key string) {
		list := controller.Center.ListDepend(mapNoId, structure.PublicDataType(t), id, key)
		//fmt.Println("list", id, key, list)
		if list == nil {
			req.Response([]*model.MapNodeInfo{})
			return
		}
		items := make([]*model.MapNodeInfo, len(list))
		//fmt.Println("list", len(list), len(items))
		for i, f := range list {
			if f == nil {
				items[i] = nil
				continue
			}
			//fmt.Println(f.ToBytes(cooperated.Position))
			position := pathfinding.DecodeVector2(f.ToBytes(cooperated.Position))
			items[i] = &model.MapNodeInfo{
				X:        int(position.X),
				Y:        int(position.Y),
				DataType: f.GetDataType(),
				Data:     f,
			}
		}
		req.Response(items)
	})

	_ = namespace.On(ManagerData, func(req *nebula.Request, mapNoId string, t byte, id interface{}) {
		dd := controller.Center.GetData(mapNoId, structure.PublicDataType(t), id)
		req.Response(dd)
	})
	_ = namespace.On(ManagerDataList, func(req *nebula.Request, mapNoId string, t byte, ids []interface{}) {
		list := controller.Center.ListData(mapNoId, structure.PublicDataType(t), ids)
		req.Response(list)
	})
}
